package com.tang.consumer.connection;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.I0Itec.zkclient.IZkChildListener;
import org.I0Itec.zkclient.ZkClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;

/**
 * @author Tang
 * @classname ServiceDiscovery
 * @description [  ]
 * @date 2021/1/24 19:23
 */
@Slf4j
@Component
public class ServiceDiscovery {

    @Value("${register.address}")
    public String registerAddress;

    @Resource
    ConnectManage connectManage;

    /**
     * 维护活着的地址列表
     */
    private final List<String> addressList = new ArrayList<>();

    private static final String ZK_REGISTRY_PATH = "/rpc";

    private ZkClient zkClient;

    @PostConstruct
    public void init() {
        if (connectServer() != null) {
            // 监视提供者节点变更

            List<String> childNode = this.zkClient.subscribeChildChanges(ZK_REGISTRY_PATH, new IZkChildListener() {
                @Override
                public void handleChildChange(String s, List<String> childNode) throws Exception {
                    log.info("监听到子节点数据变化{}", JSONObject.toJSONString(childNode));
                    addressList.clear();
                    getNodeData(childNode);
                    updateConnectServer();
                }
            });
            getNodeData(childNode);
            log.info("已发现服务列表:{}", JSON.toJSONString(addressList));
            updateConnectServer();
        }
    }

    /**
     * 更新rpc server连接地址
     */
    private void updateConnectServer() {
        connectManage.updateConnectServer(addressList);
    }

    /**
     * 获取所有的连接地址，添加到list中
     * @param childNode
     */
    private void getNodeData(List<String> childNode) {
        log.info("/rpc子节点数据为:{}", JSON.toJSONString(childNode));
        for (String node : childNode) {
            String address = this.zkClient.readData(ZK_REGISTRY_PATH + "/" + node);
            addressList.add(address);
        }
    }

    /**
     * 连接server
     * @return
     */
    private ZkClient connectServer() {
        this.zkClient = new ZkClient(registerAddress,20000,20000);
        return this.zkClient;
    }

}